home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
strategy
/
mastermi.3
/
mastermind.cc
Wrap
C/C++ Source or Header
|
1995-04-23
|
25KB
|
878 lines
/**********************************************************************
MASTERMIND player. 10 digits (0-9); words of length ln (= 2..6).
Makefile is not provided: it's too easy to compile!
compile like this: g++ -O -s -o mastermind mastermind.c -lncurses
As you can see, it requires ncurses. If you don't have this library -
get it, it's free! On the other hand, you might have curses
instead. Comment out the #include <ncurses/ncurses.h> line, uncomment
the next line (#include <curses.h>) and compile like this:
g++ -O -s -o mastermind mastermind.c -lcurses -ltermcap
Change Log:
1.3 Dec 20 1994. The word length is not a constant anymore. The
players are timed. The code is cleaned up quite a bit. It should be
faster now if you have an FPU.
1.2 Dec 12 1994. Added demo game, menus etc.
1.1 Nov 27 1994. Made the guesses to be "random" numbers. Some sort
of support for curses added.
1.0 Nov 18 1994. First written.
Copyright (C) 1994 by Semion D. Shteingold, <shteingd@math.ucla.edu>
Comments, suggestions, bug reports/fixes, flame, praise are welcome!
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with This program; see the file COPYING. If not, write to the
Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
***********************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/time.h>
#include <math.h>
#include <unistd.h>
#include <ncurses/ncurses.h>
//#include <curses.h> // If you do not have ncurses, uncomment this.
#define MLN 6 // Maximal Length of the Number
#define DEFLN 4 // DEFault Length of the Number
#define GL 20 // Maximal Length of the Game
#define VERSION "1.3"
#define NUM2STR(num, st) sprintf (st, "%.*d", ln, num)
/* Can you believe that sprintf returns <int strlen (st)> on Linux and
Solaris and <char * st> on SunOS?! */
#define MINIHELP "\tq,x: quit;\th,?: help;\tb. <- cursor -> f,\t\t"
#define LEFTMARGIN 5
#define FIRST 15 // first column
#define SECOND 55 // second column
#define SPACE 10 // dist from *'s to the replies
#define BSPACE 14 // dist from *'s to the beginning of the decsiption
#define HELPCOL 22 // the start of help in the first line
#define MSGL (LINES-2) // MeSsaGe Line
#define ASKL (LINES-2) // ASK Line
#define HLPL (LINES-HLPLEN-3) // HeLP Line
#define HLPLEN 7 // Number of lines for help
#define MHL (LINES-1) // MiniHelp Line
#define STARTL 2 // START the game from Line...
#define CLN_STR(a) { move (a, 0); clrtoeol (); }
#define MOVE_LEFT \
CLN_STR(MSGL); pos = (pos-1+ln)%ln; move (x, y+pos); refresh()
#define MOVE_RIGHT \
CLN_STR(MSGL); pos = (pos+1)%ln; move (x, y+pos); refresh()
#define MOVE_UP \
CLN_STR(MSGL); pos = (pos-1+num)%num; move(pos+STARTL,LEFTMARGIN); refresh()
#define MOVE_DOWN \
CLN_STR(MSGL); pos = (pos+1)%num; move (pos+STARTL, LEFTMARGIN); refresh()
#define MOVE_HOME_UP \
CLN_STR(MSGL); pos = 0; move (pos+STARTL, LEFTMARGIN); refresh()
#define MOVE_HOME_LEFT \
CLN_STR(MSGL); pos = 0; move (x, y+pos); refresh()
#define MOVE_END_DOWN \
CLN_STR(MSGL); pos = num-1; move (pos+STARTL, LEFTMARGIN); refresh()
#define MOVE_END_RIGHT \
CLN_STR(MSGL); pos = ln-1; move (x, y+pos); refresh()
#define PUT_HELP(text) {move(0,HELPCOL); clrtoeol(); addstr(text); refresh();}
#define GET_HELP(a) CLN_STR(MSGL); help (a); refresh(); break
#define PUT_STARS(x, y) \
{ move(x, y); for(int i=0;i<ln;i++) addch('*'); move(x,y); refresh();}
#define RND(n) ( (int) (drand48() * (n)))
#ifdef _CURSES_H
#define BEEP addch (7)
#endif
extern "C" double drand48();
extern "C" void srand48(long);
void clear_str (int, int);
void message (char *, int);
void help (int);
inline int not_valid (int);
int get_number (int, int);
int bye (int);
int ask (char * , int , int );
int play_one_game (int , int , double * , double * , int );
void play_many_games (int , int );
int menu (int , char *[]);
/*
* the length of the word. will be asked before every game.
* it is used by the class REPLY, so it has to be global. too bad...
*/
int ln = MLN;
/***************************************************************
* class REPLY.
**************************************************************/
class reply {
int b, c; // bulls & cows
public:
reply() { b = c = 0; };
~reply(){ b = c = -1;};
void compare (int, int); // how do these numbers match?
int match (int, int); // do these 2 numbers match?
void output ( int, int); // put the reply at the given position
int won() {return b == ln;};
};
int homo_guess (reply *, int *, int, int, int, int);
int incr_guess (reply *, int *, int, int, int, int);
int rand_guess (reply *, int *, int, int, int, int);
void reply::compare (int x, int y)
// compare x and y and put the result into the REPLY
{
int i, j, i10, j10;
b = c = 0;
for (i = 0, i10 = 1 ; i < ln; i++, i10 *= 10)
for (j = 0, j10 = 1 ; j < ln; j++, j10 *= 10)
if ((x/i10)%10 == (y/j10)%10) ( (i == j) ? (b++) : (c++) );
}
int reply::match (int x, int y)
// check if the x and y match the REPLY
{
int i, j, b1, c1, i10, j10;
b1 = c1 = 0;
for (i = 0, i10 = 1 ; i < ln; i++, i10 *= 10)
for (j = 0, j10 = 1 ; j < ln; j++, j10 *= 10)
if ((x/i10)%10 == (y/j10)%10) ( (i == j) ? (b1++) : (c1++) );
return (b1 == b)&& (c1 == c);
}
void reply::output (int x, int y)
// put the REPLY at (x, y)
{
mvprintw (x, y, "b:%d c:%d", b, c);
refresh();
}
// end class REPLY definition.
/*******************************************************
MAIN
*******************************************************/
int main (int argc, char *argv[])
// MasterMind Player. (Byki i Korovy)
{
int gwon = 0, glost = 0, gtie = 0;
time_t seed;
#define MAIN_MENU 5
static char * menu_lines[MAIN_MENU] =
{"This is the Main Menu", "Play a Game of Mastermind",
"Watch a DEMO game", "Help", "Exit"};
#define PARTNER 3
static char * partner[PARTNER] =
{"Choose your partner", "Dumb incremental", "Smart random"};
initscr(); // get the stdscr
cbreak(); // get each character immediately
noecho(); // no echo
scrollok (stdscr, FALSE); // do NOT scroll
mvprintw (0, 0, "MasterMind %s\tHELP: ", VERSION);
srand48 (time (&seed));
mvaddstr ( MHL, LEFTMARGIN, MINIHELP );
while (1)
{
switch ( menu (MAIN_MENU-1, menu_lines) )
{
case 0:
play_many_games (0, 1 + menu (PARTNER-1, partner ));
break;
case 1:
play_many_games (1, 2);
refresh();
break;
case 2:
help (0);
break;
case 3:
bye (0);
}
} // of while (1)
} // of main
/*******************************************************************
interface stuff.
defines:
message();
ask();
clear_str();
get_number();
help();
menu();
bye();
*******************************************************************/
void message (char * text, int bell)
// write the message; ring the bell.
{
int x, y;
getyx (stdscr, y, x);
CLN_STR(MSGL);
mvaddstr ( MSGL, LEFTMARGIN, text );
#ifdef __NCURSES_H
if (bell) beep();
#endif
#ifdef _CURSES_H
if (bell) BEEP;
#endif
move (y, x);
refresh();
return;
}
int ask (char * text, int bell, int def)
// ask a question
{
int x, y, ans;
getyx (stdscr, y, x);
CLN_STR(ASKL);
mvaddstr ( ASKL, LEFTMARGIN, text );
#ifdef __NCURSES_H
if (bell) beep();
#endif
#ifdef _CURSES_H
if (bell) BEEP;
#endif
addstr ( (def == 0) ? " (n)..." : " (y)..." );
refresh();
ans = tolower (getch());
ans = ( ans =='y' ) || ( (def) && (ans != 'n') );
addstr ( (ans) ? "Yes." : "No.");
move (y, x);
refresh();
return (ans);
}
void clear_str (int beg, int end)
// clear the specified area.
{
int x, y, i;
getyx (stdscr, y, x);
for (i = beg; i <= end; i++) CLN_STR(i);
move (y, x);
refresh();
return;
}
int get_number (int x, int y)
// get an ln-digit number in_num at position (x, y).
{
int in_num = 0, pos = 0, c, i, flag;
int entered[MLN];
for (i = 0; i < ln; i++) entered[i] = 10;
move (x, y);
refresh();
while (1)
{
switch (c = tolower (getch()))
{
case ',': case 2: /* ^B */ case 'b':
case 'p': case 16: /* ^P */ case '<':
MOVE_LEFT;
break;
case '.': case 6: /* ^F */ case 'f':
case 'n': case 14: /* ^N */ case '>':
MOVE_RIGHT;
break;
case 1: /* ^A */ case 'a':
MOVE_HOME_LEFT;
break;
case 5: /* ^E */ case 'e':
MOVE_END_RIGHT;
break;
case 27: /* ESC */
switch (tolower (getch()))
{
case 'o': case 91: /* [ */
switch (tolower (getch()))
{
case 'a': case 'd':
MOVE_LEFT;
break;
case 'b': case 'c':
MOVE_RIGHT;
break;
case '7': /* home */
MOVE_HOME_LEFT;
getch();
break;
case '8': /* end */
MOVE_END_RIGHT;
getch();
break;
default:
while (getch()!='~');
GET_HELP(1);
}
break;
default:
GET_HELP(1);
}
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (i = 0; (i < ln) && ( (c-'0') != entered[i]) ; i++);
if ( ( (c-'0') == entered[i]) && (i != ln) )
message ("You already have this digit!", 1);
else
{
entered[pos] = c-'0';
addch (c);
MOVE_RIGHT;
}
break;
case 'h': case '?':
GET_HELP(1);
case 127: /* ^? */ case 8: /* ^H */
MOVE_LEFT;
case 32:
addch ('*'); entered[pos] = 10; move (x, y+pos); break;
case 10: // Enter
for (in_num = i = 0, flag = 1; (i < ln) && (flag) ; i++)
if (entered[i] == 10) flag = 0;
else in_num = in_num*10+entered[i];
if (flag)
{
CLN_STR(MSGL);
return (in_num);
}
else
{
in_num = 0;
message ("You have not entered the number yet!", 1);
}
break;
case 'q': case 'x': case 3: /* ^C */
if (ask ("Are you sure you want to quit?", 0, 0)) return (-1);
case 12: /* ^L */ case 18: /* ^R */
// redrawln (stdscr, 0, 24); break;
message ("sorry, cannot redraw screen yet", 1); break;
default:
message ("Illegal key. Please use \"h\" or \"?\" for help.", 1);
break;
}
refresh();
} // end of while (1)
} // get_number
void help (int num)
/*******************************************
give help according to the context:
0: general;
1: get_number;
2: license;
3: send e-mail to the author;
then return to the initial position of the cursor.
*******************************************/
{
int x, y;
getyx (curscr, x, y);
clear_str (HLPL, MHL);
mvaddstr ( MHL, 0, "G - general help; also: N; L; M." );
switch (num)
{
case 0:
clear_str (HLPL, HLPL+HLPLEN);
mvaddstr ( HLPL, 0, "\tHELP: General:\n\t\
This is a game. You and I think of a number, and each tries\n\t\
to guess the number of the other. The answer is displayed\n\t\
to the right in the form: \"b:2 c:1\". This means that\n\t\
the number to the left has 3 common digits with the number\n\t\
being guessed, 2 of them on the right position and one on\n\t\
on the wrong.");
message ("Press any key to continue...", 0);
getch();
clear_str (HLPL+1, HLPL+HLPLEN);
mvaddstr ( HLPL+1, 0 , "\t\
More help: N - how to enter a number; L - see the license;\n\t\
M - send mail to the author.\n\t\
Beware: sending mail will terminate the program!\n\t\
G - see the general help again.");
refresh();
CLN_STR(MSGL);
break;
case 1:
clear_str (HLPL, HLPL+HLPLEN);
mvaddstr ( HLPL, 0 , "\tHELP: Entering a number:\n\t\
You should enter a \"valid\" number.\n\t\
A number is \"valid\" if it contains digits \'0\' to \'9\'\n\t\
and does not have the same digit twice. The number can\n\t\
start with 0. Use the space bar to erase the curent digit,\n\t\
and the <,b, and >,f keys to move within the allotted space.\n\t\
You can use the BS/DEL keys. The arrows should also work.");
refresh();
break;
case 2:
clear_str (HLPL, HLPL+HLPLEN);
mvaddstr ( HLPL, 0, "\tHELP: License information:\n\t\
Copyright (C) 1994 by Sam Shteingold, <shteingd@math.ucla.edu>\n\t\
Comments, suggestions, bug reports/fixes are welcome!\n\t\
This program is free software; you can redistribute it and/or modify\n\t\
it under the terms of the GNU General Public License as published by\n\t\
the Free Software Foundation; either version 2, or (at your option)\n\t\
any later version.");
message ("Press any key to continue...", 0);
getch();
clear_str (HLPL+1, HLPL+HLPLEN);
mvaddstr ( HLPL+1, 0, "\t\
This program is distributed in the hope that it will be useful, but\n\t\
WITHOUT ANY WARRANTY; without even the implied warranty of\n\t\
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n\t\
General Public License for more details.\n\t\
You should have received a copy of the GNU General Public License\n\t\
along with This program; see the file COPYING. If not, write to the\n\t\
Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.");
refresh();
CLN_STR(MSGL);
break;
case 3:
nocbreak();
echo();
clear ();
mvaddstr (0,0, "Enter the message. Terminate by a single dot on the line.\n");
refresh();
system ("mail shteingd@math.ucla.edu -s \"I use mastermind...\"");
// cbreak(); noecho(); redrawwin (stdscr); break;
bye (0);
} // of switch (num);
switch (tolower (getch()))
{
case 'g':
help (0); break;
case 'n':
help (1); break;
case 'l':
help (2); break;
case 'm':
help (3); break;
default:
clear_str (HLPL, LINES);
mvaddstr (MHL, LEFTMARGIN, MINIHELP);
}
move (x, y);
refresh();
return;
} // help
int menu (int num, char * items[])
// chose an item in the menu
// num items; items[0] = title; others - lables of the items
{
int pos = 0, c, i;
clear_str (1, MSGL);
PUT_HELP(items[0]);
for (i = 1; i <= num; i++)
mvprintw (i + STARTL - 1 , LEFTMARGIN, "%d. %s", i, items[i]);
move (STARTL, LEFTMARGIN);
refresh();
while (1)
{
switch (c = tolower (getch()))
{
case ',': case 16: /* ^P */ case 2: /* ^B */ case 'b': case 'p':
case 'k': case 127: /* ^? */ case 8: /* ^H */ case '<':
MOVE_UP; break;
case '.': case 14: /* ^N */ case 6: /* ^F */ case 'f': case 'n':
case 'j': case 32: /* SP */ case '>':
MOVE_DOWN; break;
case 1: /* ^A */ case 'a':
MOVE_HOME_UP; break;
case 5: /* ^E */ case 'e':
MOVE_END_DOWN; break;
case 27: /* ESC */
switch (tolower (getch()))
{
case 'o': case 91: /* [ */
switch (tolower (getch()))
{
case 'a': /* ^ */ case 'd': /* < */
MOVE_UP;
break;
case 'b': /* > */ case 'c': /* v */
MOVE_DOWN;
break;
case '7': /* home */
MOVE_HOME_UP;
getch();
break;
case '8': /* end */
MOVE_END_DOWN;
getch();
break;
default:
while (getch() != '~');
GET_HELP(0);
}
break;
default:
GET_HELP(0);
}
break;
case 'h': case '?':
GET_HELP(0);
case 10: // Enter
return (pos);
case 'q': case 'x': case 3: /* ^C */
bye (0);
case 12: /* ^L */ case 18: /* ^R */
//redrawln (stdscr, 0, 24); break;
message ("sorry, cannot redraw screen yet", 1);
break;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (c-'1' < num) return (c-'1');
default:
message ("Illegal key. Please use \"h\" or \"?\" for help.", 1);
break;
}
refresh();
}
} // menu
int bye (int i)
{
CLN_STR(LINES-1);
nocbreak();
echo();
move (LINES-1, 0);
refresh();
endwin();
exit (i);
}
// end of interface
/*******************************************************************
algorithm only. Uses:
message();
get_number().
ask();
*******************************************************************/
int play_one_game (int first, int second, double * f_tm, double * s_tm,
int max_num)
/**************
play Mastermind just once.
first/second:
0: human; first AND second cannot be 0 BOTH at the same time;
1: computer, incremental;
2: computer, random.
returns:
0: tie;
1: first won;
-1: second won;
10: error.
**************/
{
struct timeval tm1, tm2;
struct timezone tzp;
int frs_num, sec_num, round;
reply frs_reps[GL], sec_reps[GL];
int frs_ask[GL], sec_ask[GL];
int (*frs_get) (reply *, int *, int, int, int, int);
int (*sec_get) (reply *, int *, int, int, int, int);
#define NUMLN 5
static char * lines[NUMLN] = {"Are you still there?! You are very daring!",
"No result yet, but somehow I'm sure I'll win.",
"You think slowly. I bet you are a mere human!",
"Your case is hopeless. Surrender!",
"Why don\'t you just give up?!"};
if ( (first == 0) && (second == 0))
{
message ("both cannot be humans!", 1);
return 10;
}
clear_str (STARTL, MSGL-1);
// the framework:
switch (first)
{
case 0:
mvaddstr (STARTL, FIRST-BSPACE, "1:Human - #:");
mvaddstr (STARTL+1, SECOND-BSPACE, " H guesses:");
frs_get = & homo_guess;
break;
case 1:
mvaddstr (STARTL, FIRST-BSPACE, "1:CIncr - #:");
mvaddstr (STARTL+1, SECOND-BSPACE, " CI guesses:");
frs_get = & incr_guess;
break;
case 2:
mvaddstr ( STARTL, FIRST-BSPACE, "1:CRand - #:");
mvaddstr ( STARTL+1, SECOND-BSPACE, " CR guesses:");
frs_get = & rand_guess;
break;
default:
message ("wrong first argument in play_one_game. hit a key\t\t", 1);
getch();
return (10);
}
PUT_STARS(STARTL, FIRST)
switch (second)
{
case 0:
mvaddstr (STARTL, SECOND-BSPACE, "2:Human - #:");
mvaddstr (STARTL+1, FIRST-BSPACE, " H guesses:");
sec_get = & homo_guess;
break;
case 1:
mvaddstr (STARTL, SECOND-BSPACE, "2:CIncr - #:");
mvaddstr (STARTL+1, FIRST-BSPACE, " CI guesses:");
sec_get = & incr_guess;
break;
case 2:
mvaddstr (STARTL, SECOND-BSPACE, "2:CRand - #:");
mvaddstr (STARTL+1, FIRST-BSPACE, " CR guesses:");
sec_get = & rand_guess;
break;
default:
message ("wrong second argument in play_one_game. hit a key\t\t", 1);
getch();
return (10);
}
PUT_STARS (STARTL, SECOND)
// get the numbers to be guessed.
if (first)
{
do frs_num = RND(max_num);
while (not_valid (frs_num));
}
else
{
PUT_HELP("Enter your secret number, then press <Enter>.");
if ( (frs_num = get_number (STARTL, FIRST)) == -1) return (10);
}
if (second)
{
do sec_num = RND(max_num);
while (not_valid (sec_num));
}
else
{
PUT_HELP("Enter your secret number, then press <Enter>.");
if ( (sec_num = get_number (STARTL, SECOND)) == -1) return (10);
}
round = 0;
do
{
// do the moves:
gettimeofday(&tm1, &tzp);
if ( ( (*frs_get) (frs_reps, frs_ask, SECOND,
round, max_num, sec_num)) == -1)
return (10);
gettimeofday(&tm2, &tzp);
*f_tm += (double) (tm2.tv_sec - tm1.tv_sec) +
( (double) (tm2.tv_usec - tm1.tv_usec) )/1000000;
refresh();
gettimeofday(&tm2, &tzp);
if ( ( (*sec_get) (sec_reps, sec_ask, FIRST ,
round, max_num, frs_num)) == -1)
return (10);
gettimeofday(&tm2, &tzp);
*s_tm += (double) (tm2.tv_sec - tm1.tv_sec) +
( (double) (tm2.tv_usec - tm1.tv_usec) ) /1000000;
refresh();
// the results of the round:
if ( (frs_reps[round].won())&& (sec_reps[round].won())) return (0); //tie
else if ( (! (frs_reps[round].won()))&& (sec_reps[round].won()))
{
mvprintw ( STARTL, SECOND, "%.*d", ln, sec_num);
refresh();
return (-1);
}
else if ( (frs_reps[round].won())&& (! (sec_reps[round].won())))
{
mvprintw (STARTL, FIRST, "%.*d", ln, frs_num);
refresh();
return (1);
}
else if (! (first*second)) message (lines[RND(NUMLN)], 0);
}
while (round++ < GL);
} // of play_one_game
int rand_guess (reply reps[GL], int old_guess[GL], int pos,
int round, int max_num, int secret)
/********
make a random guess of SECRET, which is up to MAX_NUM; put at collumn POS.
use old guesses OLD_GUESS with replies REPS in ROUND.
********/
{
int j, i, ini, num_ok = 0;
ini = RND(max_num);
PUT_STARS(STARTL+1+round, pos)
message ("CRand is thinking. Please wait...", 0);
if (drand48() > 0.5)
{ // go up
for (i = ini+1; (i != ini) && (!num_ok) ; i = ( i + 1 ) % max_num )
if (!not_valid (i))
for (j = 0, num_ok = 1 ; (j < round) && (num_ok) ; j++)
num_ok *= reps[j].match (i, old_guess[j]);
old_guess[round] = ( i - 1 + max_num ) % max_num;
}
else
{ // go down
for (i = ini-1; (i != ini) && (!num_ok) ; i = ( i - 1 + max_num ) % max_num )
if (!not_valid (i))
for (j = 0, num_ok = 1 ; (j < round) && (num_ok) ; j++)
num_ok *= reps[j].match (i, old_guess[j]);
old_guess[round] = ( i + 1 ) % max_num;
}
if (i == ini) { message ("Random: ERROR! hit a key", 1); getch(); }
mvprintw (STARTL+1+round, pos, "%.*d", ln, old_guess[round]);
reps[round].compare (old_guess[round], secret);
reps[round].output (STARTL+1+round, pos+SPACE);
return (old_guess[round]);
} // rand_guess
int incr_guess (reply reps[GL], int old_guess[GL], int pos,
int round, int max_num, int secret)
/*****
make an incremental guess of SECRET, which is up to MAX_NUM; put at
collumn POS. use old guesses OLD_GUESS with replies REPS in ROUND.
*****/
{
int j, i, ini, num_ok = 0;
PUT_STARS(STARTL+1+round, pos)
message ("CIncr is thinking. Please wait...", 0);
(round) ? (i = old_guess[round-1]) : (i = 0);
for (i++, num_ok = 0; (i < max_num) && (!num_ok); i++)
if (!not_valid (i))
for (j = 0, num_ok = 1; (j < round) && (num_ok) ; j++)
num_ok *= reps[j].match (i, old_guess[j]);
if (i == max_num) { message ("Incremental: ERROR! hit a key", 1); getch(); }
old_guess[round] = --i;
mvprintw (STARTL+1+round, pos, "%.*d", ln, old_guess[round]);
reps[round].compare (old_guess[round], secret);
reps[round].output (STARTL+1+round, pos+SPACE);
return (old_guess[round]);
} // incr_guess
int homo_guess (reply reps[GL], int old_guess[GL], int pos,
int round, int max_num, int secret)
// get the human player's guess.
{
PUT_STARS(STARTL+1+round, pos)
PUT_HELP("Enter your guess, then press <Enter>.");
old_guess[round] = get_number (STARTL+1+round, pos);
reps[round].compare (old_guess[round], secret);
reps[round].output (STARTL+1+round, pos+SPACE);
return (old_guess[round]);
}
void play_many_games (int f, int s)
// play several games, keeping the score.
{
int first = 0, second = 0, tie = 0, i;
int max_num = 1; // 10^ln
double f_tm = 0, s_tm = 0;
// get ln:
PUT_HELP ("What will the length of the number be?");
clear_str (STARTL, MSGL);
mvaddstr (HLPL, 0, "\tPlease enter the length of the word.\n\t\
You should enter a reasonable number:\n\t\
2 is too short - it won't be interesting, \n\t\
6 is too long - it'll take me too long\n\t\
to produce each guess.\n\t\
The reasonable number is, probably, 4, \n\t\
but 3 also might be interesting.");
mvprintw ( MSGL, LEFTMARGIN,
"Enter number from 2 to %d. Default is %d ...", MLN, DEFLN );
refresh();
ln = getch() - '0';
if ( (ln < 2) || (ln > MLN)) ln = DEFLN;
clear_str (HLPL, MSGL);
// if not a demo, get_number will say something...
PUT_HELP("Demo game...");
// initialization of 'max_num'.
for (i = 0; i < ln; i++) max_num *= 10;
do
{
switch (play_one_game (f, s, & f_tm, & s_tm, max_num))
{
case 0 :
if (f*s == 0) PUT_HELP ("Uphhh... Tie! That was close!");
tie++ ; break;
case 1 :
if (f == 0) PUT_HELP ("Ouch! You are SMART! You beat me!");
if (s == 0) PUT_HELP ("As one could expect, you lost.");
first++; break;
case -1:
if (s == 0) PUT_HELP ("Ouch! You are SMART! You beat me!");
if (f == 0) PUT_HELP ("As one could expect, you lost.");
second++; break;
}
mvprintw (1, 1, "1:%d; 2:%d; tie:%d; games:%d; time: 1:%.3f sec; 2:%.3f sec.",
first, second, tie, first+second+tie, f_tm, s_tm);
mvprintw (STARTL, FIRST + SPACE, "(won: %d)", first);
mvprintw (STARTL, SECOND + SPACE, "(won: %d)", second);
}
while (ask ("The game is over. Again?", 0, 1));
clear_str (STARTL-1, MSGL);
} // play_many_games
inline int not_valid (int x)
/***************************************
Check if the number 'x' is valid. Return 0 if valid; or the second
part or the first bad spot: for number 4598595 returns 4 - the
position of the second "5".
To save time does NOT check x < 10^ln. BEWARE!
***************************************/
{
int i, j, i10, j10;
for (i = 1, i10 = 10 ; i < ln; i++, i10 *= 10)
for (j = 0, j10 = 1 ; j < i; j++, j10 *= 10)
if ( (x/i10)%10 == (x/j10)%10 ) return (i);
return (0);
}